# File: src/mcp_server/app.py
# Purpose: Defines the MCP server instance, lifespan, and ASGI app.

import logging
from contextlib import asynccontextmanager
from collections.abc import AsyncIterator
from typing import Dict, Any

# Import MCP components correctly from the SDK
from mcp.server.fastmcp import FastMCP, Context

# Import core application components
from ..core.config import load_config, get_config_value
from ..core.exceptions import MCPServerError
from ..core.logging_setup import get_logger

# Import skills lifecycle management
from ..skills.web_automation.manager import start_playwright, stop_playwright

# Import your application's shared context definition
from .context import ServerContext

# --- Initialize Logger ---
# Ensures logger is available for setup messages
logger = get_logger("mcp_server_app")

# --- Define Application Lifespan ---
@asynccontextmanager
async def app_lifespan(server: FastMCP) -> AsyncIterator[ServerContext]:
    """
    Manages application-level resources like Playwright and configuration
    throughout the server's lifespan.
    """
    logger.info("MCP server lifespan starting...")
    app_config = {}
    server_ctx = ServerContext(app_config={}) # Initialize application context

    try:
        # Load configuration early in the lifespan
        # This makes it available via context if needed by startup tasks
        server_ctx.app_config = load_config()
        logger.info("Configuration loaded within lifespan.")

        # Start Playwright using the loaded configuration
        web_skill_config = server_ctx.get_skill_config("web_automation")
        if not web_skill_config:
             logger.warning("Web automation skill config not found in lifespan, using defaults for Playwright.")
        await start_playwright(config=web_skill_config)
        logger.info("Playwright started successfully via lifespan.")

        # Yield the application context, making it available in request handlers
        # via ctx.request_context.lifespan_context
        yield server_ctx
        logger.info("MCP server lifespan running.")

    except Exception as e:
        logger.critical(f"Critical error during server startup within lifespan: {e}", exc_info=True)
        # Ensure cleanup is attempted even if startup fails partially
        raise MCPServerError(f"Server startup failed during lifespan: {e}") from e
    finally:
        # Cleanup resources on shutdown
        logger.info("MCP server lifespan shutting down...")
        try:
            await stop_playwright()
            logger.info("Playwright stopped successfully via lifespan.")
        except Exception as stop_err:
            logger.error(f"Error during Playwright shutdown in lifespan: {stop_err}", exc_info=True)
        logger.info("MCP server lifespan finished.")


# --- Create and Configure the FastMCP Instance ---
logger.info("Creating FastMCP instance...")
try:
    # Load server-specific configuration
    server_config = get_config_value("mcp_server", {})
    mcp_server_name = server_config.get("name", "LLM_MCP_Agent_Server_Default")
    mcp_server_description = server_config.get("description", "Default Agent Server Description")

    # Instantiate FastMCP, passing the lifespan manager
    mcp = FastMCP(
        name=mcp_server_name,
        description=mcp_server_description,
        lifespan=app_lifespan # IMPORTANT: Integrate the lifespan here
        # Add dependencies if needed for deployment packaging, e.g.:
        # dependencies=["playwright", "openai"]
    )
    logger.info(f"FastMCP instance '{mcp.name}' created successfully with lifespan.")

except Exception as instance_err:
    logger.critical(f"Failed to create FastMCP instance: {instance_err}", exc_info=True)
    raise MCPServerError(f"Failed to create FastMCP instance: {instance_err}") from instance_err

# --- Import Tool and Resource Modules ---
# Importing these modules registers the tools/resources defined within them
# using the @mcp.tool and @mcp.resource decorators on the 'mcp' instance above.
logger.info("Importing and registering MCP tools and resources...")
try:
    from .tools import web_automation_tools
    from .resources import health_resource
    # Import other tool/resource modules here if you add more
    logger.info("Tools and resources imported successfully.")
except Exception as import_err:
    logger.critical(f"Failed to import MCP tools/resources: {import_err}", exc_info=True)
    # Depending on severity, you might want to raise an error here
    # raise MCPServerError(f"Failed to import tools/resources: {import_err}") from import_err


# --- Create the ASGI Application ---
# This creates the Starlette app that Uvicorn will run for SSE communication.
try:
    app = mcp.sse_app()
    logger.info("ASGI application (app = mcp.sse_app()) created successfully.")
except Exception as sse_app_err:
     logger.critical(f"Failed to create ASGI app via mcp.sse_app(): {sse_app_err}", exc_info=True)
     raise MCPServerError(f"Failed to create ASGI app: {sse_app_err}") from sse_app_err